#!/usr/bin/env python
# -*- coding: utf-8 -*-

import threading
from threading import Thread
import subprocess
from subprocess import PIPE, STDOUT
import time


from loguru import logger

# generate an object of CallAcqDriverControl each acquisition 
class CallAcqDriverControl(object):
    def __init__(self):
        super().__init__()

        # record the console output
        self.g_demo_con_ouput = []
        self.g_mutex = threading.Lock()
        self.g_con_task_flag = True
        self.g_con_log_index = -1

        self.subp = None
        self.con_task = None

    # parse the script file
    def __parseScript(self, script):
        cmds = []

        with open(script, 'r', encoding='utf-8') as file:
            for line in file.readlines():
                line = line.strip()
                if line == "":
                    continue
                if line.startswith('//'): #comments
                    continue
                cmds.append(line)

        logger.debug("parse script {0} successfully.", script)
        return cmds

    # run a subprocess of ControlNodeDrvDemo.exe
    def __startProcess(self, exe_path, output_path):
        subp = subprocess.Popen([exe_path, output_path], bufsize=0, stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=False)
        logger.debug("start process {0} successfully.", exe_path)
        return subp
    
    # start a thread
    # read console log and save into demo_con_ouput
    def __readConsoleRemaining(self, stream):
        while self.g_con_task_flag:
            con = stream.readline()
            if not con:
                continue
            
            self.g_mutex.acquire()
            try:
                #logger.debug("console output log is: {}", con)
                constr = con.decode('utf-8')
                self.g_demo_con_ouput.append(constr)
            except Exception as error:
                logger.error(error)
            self.g_mutex.release()
    
    def __runDemoCommand(self, subp, cmd):
        cmd = cmd + '\n'
        
        self.g_mutex.acquire()
        logger.debug("input console cmd is: {}", cmd)
        subp.stdin.write(cmd.encode('utf-8'))
        self.g_mutex.release()
        
        #time.sleep(0.2)  # TODO：too long? 
        
        self.g_mutex.acquire()
        ncon_line = len(self.g_demo_con_ouput)
        ret = 1
        
        if self.g_con_log_index < ncon_line-1:
            for i in range(self.g_con_log_index + 1, ncon_line):
                line = self.g_demo_con_ouput[i]
                #logger.debug("console output is: {}", line)
                if 'error' in line.lower():
                    ret = 0
            self.g_con_log_index = ncon_line - 1
        self.g_mutex.release()
        
        return ret

        # driver_control_exe_path    path of ControlNodeDrvDemo.exe    
        # script_path                path of acquisition output
        # output_path                path of input script
    def processOneAcq(self, driver_control_exe_path, script_path, output_path):
        logger.debug("start processOneAcq. driver_control_exe_path:{0}, script_path:{1}, output_path:{2}", driver_control_exe_path, script_path, output_path)
        self.g_con_task_flag = True
        self.subp = self.__startProcess(driver_control_exe_path, output_path)
        self.con_task = Thread(target = self.__readConsoleRemaining, args=[self.subp.stdout])
        self.con_task.start()
        
        self.__runDemoCommand(self.subp, 'Open')
        cmds = self.__parseScript(script_path)
        for cmd in cmds:
            self.__runDemoCommand(self.subp, cmd)
        
        logger.debug("end processOneAcq.")
    
    def endAcq(self):
        logger.debug("start endAcq.")
        self.__runDemoCommand(self.subp, 'exit')
        self.g_con_task_flag = False
        self.subp.terminate()
        self.con_task.join()
        #self.g_con_task_flag = False
        self.g_demo_con_ouput.clear()
        self.g_con_log_index = -1

        logger.debug("end endAcq successfully.")


if __name__ == '__main__':
    callDriverControl = CallAcqDriverControl()
    driver_control_exe_path = "D:/Project/acq_cmd_script/ControlNodeDrvDemo.exe"
    script_path = "D:/Project/acq_cmd_script/REG_CMD_Line_Config.vh"
    output_path = "D:/Project/Data"
    callDriverControl.processOneAcq(driver_control_exe_path, script_path, output_path)
    callDriverControl.endAcq()
